﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace InCall_Lock
{
    public class HookKeys
    {
        #region delegates
        public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
        public delegate void HookEventHandler(HookEventArgs e, KeyBoardInfo keyBoardInfo);
        public HookEventHandler HookEvent;
        #endregion
        
        #region fields
        private HookProc hookDeleg;
        private static int hHook = 0;
        #endregion

        public HookKeys()
        {
        }

        #region public methods
        /// 
        /// Starts the hook
        /// 

        public void Start()
        {
            if (hHook != 0)
            {
                //Unhook the previouse one
                this.Stop();
            }
            hookDeleg = new HookProc(HookProcedure);
            hHook = SetWindowsHookEx(WH_KEYBOARD_LL, hookDeleg, GetModuleHandle(null), 0);
            if (hHook == 0)
            {
                throw new SystemException("Failed acquiring of the hook.");
            }
            //else
            //    Log.Append("Hook acquired");
        }
        /// 
        /// Stops the hook
        /// 
        public void Stop()
        {
            UnhookWindowsHookEx(hHook);
        }
        #endregion

        #region protected and private methods
        protected virtual void OnHookEvent(HookEventArgs hookArgs, KeyBoardInfo keyBoardInfo)
        {
            if (HookEvent != null)
            {
                HookEvent(hookArgs, keyBoardInfo);
            }
        }
        private int HookProcedure(int code, IntPtr wParam, IntPtr lParam)
        {
           KBDLLHOOKSTRUCT hookStruct =  (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
           if (code < 0)
               return CallNextHookEx(hookDeleg, code, wParam, lParam);
           // Let clients determine what to do
           HookEventArgs e = new HookEventArgs();
           e.Code = code;
           //Log.Append("Code is: " + e.Code);
           e.wParam = wParam;
           //Log.Append("wParam is: " + e.wParam);
           e.lParam = lParam;
           //Log.Append("lParam is: " + e.lParam);
           KeyBoardInfo keyInfo = new KeyBoardInfo();
           keyInfo.vkCode = hookStruct.vkCode;
           //Log.Append("vkCode is: " + keyInfo.vkCode);
           keyInfo.scanCode = hookStruct.scanCode;
           //Log.Append("scanCode is: " + keyInfo.scanCode);
           keyInfo.flags = hookStruct.flags;
           //Log.Append("flags: " + keyInfo.flags);
           keyInfo.time = hookStruct.time;
           //Log.Append("time is: " + keyInfo.time);
           keyInfo.dwExtraInfo = hookStruct.dwExtraInfo;
           //Log.Append("Extra info: " + keyInfo.dwExtraInfo);
           OnHookEvent(e, keyInfo);
           // Yield to the next hook in the chain
           if (Program.overrideDefault)
               return -1;
           else
               return CallNextHookEx(hookDeleg, code, wParam, lParam);
       }
        #endregion

        #region P/Invoke declarations
       [DllImport("coredll.dll")]
       private static extern int SetWindowsHookEx(int type, HookProc hookProc, IntPtr hInstance, int m);

        [DllImport("coredll.dll")]
       private static extern IntPtr GetModuleHandle(string mod);

       [DllImport("coredll.dll")]
       private static extern int CallNextHookEx(
               HookProc hhk,
               int nCode,
               IntPtr wParam,
               IntPtr lParam
               );

       [DllImport("coredll.dll")]
       private static extern int GetCurrentThreadId();

       [DllImport("coredll.dll", SetLastError = true)]
       private static extern int UnhookWindowsHookEx(int idHook);

       private struct KBDLLHOOKSTRUCT
       {
           public int vkCode;
           public int scanCode;
           public int flags;
           public int time;
           public IntPtr dwExtraInfo;
       }

       const int WH_KEYBOARD_LL = 20;
       #endregion

    }
    #region my stuff
    public static class ProcessKey
    {
        //
        public static DateTime nextClickTime = DateTime.Now;//{ get; set; }
        public static bool isDoubleClick()
        {
            //
                //
            int withinTimeLimit = DateTime.Now.CompareTo(nextClickTime);
            if (withinTimeLimit <= 0)
            {
                return true;
            }
            else
                return false;
        }
    }
    #endregion

    #region event arguments
    public class HookEventArgs : EventArgs
    {
        public int Code;    // Hook code
        public IntPtr wParam;   // WPARAM argument
        public IntPtr lParam;   // LPARAM argument
    }

    public class KeyBoardInfo
    {
        public int vkCode;
        public int scanCode;
        public int flags;
        public int time;
        public IntPtr dwExtraInfo;
    }
        #endregion
    //}
}
